﻿using System;
using System.Linq;
using Entities;
using ServiceContracts;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Client.Test
{
    [TestClass]
    public class UnitTest
    {
        [TestMethod]
        public void TestService()
        {
            INorthwindService context = new NorthwindClientContext { LazyLoadingEnabled = false };
            Assert.IsTrue(context.GetCustomers().Any());
        }

        [TestMethod]
        public void TestFilter()
        {
            INorthwindService context = new NorthwindClientContext { LazyLoadingEnabled = false };
            Assert.AreEqual(1, context.GetCustomers(null, "it.CustomerID='ALFKI'", null, null, null).Count);
        }

        [TestMethod]
        public void TestLINQWhere()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
                                    where c.CustomerID == "ALFKI"
                                    select c).Count());
            }
        }

        [TestMethod]
        public void TestLINQWhere2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var customerID = "ALFKI";
                Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
                                    where c.CustomerID == customerID
                                    select c).Count());
            }
        }

        [TestMethod]
        public void TestLINQWhere3()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var customer = new Customer { CustomerID = "ALFKI" };
                Assert.AreEqual(1, (from c in context.Customers.AsQueryable()
                                    where c.CustomerID == customer.CustomerID
                                    select c).Count());
            }
        }

        [TestMethod]
        public void TestLINQWhere4()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.IsTrue((from o in context.Orders.AsQueryable()
                               where o.OrderDate > new DateTime(1997, 1, 31)
                               select o).Any());
            }
        }

        [TestMethod]
        public void TestLINQWhere5()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var d = new DateTime(1997, 1, 31);
                Assert.IsTrue((from o in context.Orders.AsQueryable()
                               where o.OrderDate > d
                               select o).Any());
            }
        }

        [TestMethod]
        public void TestLINQWhere6()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.IsTrue((from c in context.Customers.AsQueryable()
                               where c.Orders.Any()
                               select c).Any());
            }
        }

        [TestMethod]
        public void TestLINQWhere7()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.IsTrue((from c in context.Customers.AsQueryable()
                               where c.Orders.Any(o => o.OrderDate > new DateTime(1997, 1, 1))
                               select c).Any());
            }
        }

        [TestMethod]
        public void WhereParentesis()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var employees = (from e in context.Employees.AsQueryable()
                                 where (e.Address.City == "Paris" || (e.Address.City == "London")) && e.BirthDate < new DateTime(1970, 1, 1)
                                 select e).ToList();
                var expectedResult = (from e in context.Employees.AsQueryable().AsEnumerable()
                                        where (e.Address.City == "Paris" || (e.Address.City == "London")) && e.BirthDate < new DateTime(1970, 1, 1)
                                        select e).ToList();
                Assert.AreEqual(expectedResult.Count, employees.Count);
            }
        }

        [TestMethod]
        public void TestLINQTake()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.AreEqual(2, (from c in context.Customers.AsQueryable()
                                    select c).Take(2).Count());
            }
        }

        [TestMethod]
        public void TestFirstAndInclude()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var order = (from o in context.Orders.AsQueryable().Include(Order.CUSTOMER_NAME).Include(Order.ORDERDETAILS_NAME)
                             where o.ShipAddress.City == "PARIS"
                             orderby o.OrderDate
                             select o).Skip(2).First();
                Assert.IsNotNull(order.Customer);
                Assert.AreEqual(1, context.Customers.Count);
                Assert.AreEqual(order.Customer, context.Customers[0]);
                Assert.AreEqual(1, context.Orders.Count);
                Assert.AreEqual(order, context.Orders[0]);
                Assert.IsTrue(order.OrderDetails.Any());
            }
        }

        [TestMethod]
        public void TestFirstAndIncludeWithFunc()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var order = (from o in context.Orders.AsQueryable().Include(o => o.Customer).Include(o => o.OrderDetails)
                             where o.ShipAddress.City == "PARIS"
                             orderby o.OrderDate
                             select o).Skip(2).First();
                Assert.IsNotNull(order.Customer);
                Assert.AreEqual(1, context.Customers.Count);
                Assert.AreEqual(order.Customer, context.Customers[0]);
                Assert.AreEqual(1, context.Orders.Count);
                Assert.AreEqual(order, context.Orders[0]);
                Assert.IsTrue(order.OrderDetails.Any());
            }
        }

        [TestMethod]
        public void OfType()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var employeesInActivity = context.Employees.AsQueryable().OfType<EmployeeInActivity>().ToList();
                Assert.IsTrue(employeesInActivity.Any());
                Assert.AreEqual(employeesInActivity.Count, context.Employees.Count);
                Assert.AreEqual(employeesInActivity.Count, context.EmployeeInActivities.Count);
                Assert.IsFalse(context.OutEmployees.Any());
            }
        }

        [TestMethod]
        public void NoTracking()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.NoTracking;
                var l = context.Customers.AsQueryable().ToList();
                Assert.IsFalse(context.Customers.Any());
                Assert.IsTrue(l.Any());
            }
        }

        [TestMethod]
        public void AppendOnly()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.AppendOnly;
                var l = context.Customers.AsQueryable().ToList();
                Assert.AreEqual(l.Count, context.Customers.Count);
            }
        }

        [TestMethod]
        public void AppendOnly2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.AppendOnly;
                var c = new Customer { CustomerID = "ALFKI" };
                context.Customers.Attach(c);
                context.Customers.AsQueryable().ToList();
                Assert.IsNull(c.CompanyName);
                Assert.IsFalse(c.ChangeTracker.ModifiedProperties.Any());
            }
        }

        [TestMethod]
        public void OverwriteChanges()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.OverwriteChanges;
                var l = context.Customers.AsQueryable().ToList();
                Assert.AreEqual(l.Count, context.Customers.Count);
            }
        }

        [TestMethod]
        public void OverwriteChanges2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.OverwriteChanges;
                var c = new Customer { CustomerID = "ALFKI" };
                context.Customers.Attach(c);
                context.Customers.AsQueryable().ToList();
                Assert.IsNotNull(c.CompanyName);
                Assert.IsFalse(c.ChangeTracker.ModifiedProperties.Any());
            }
        }

        [TestMethod]
        public void PreserveChanges()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.PreserveChanges;
                var l = context.Customers.AsQueryable().ToList();
                Assert.AreEqual(l.Count, context.Customers.Count);
            }
        }

        [TestMethod]
        public void PreserveChanges2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.MergeOption = MergeOption.PreserveChanges;
                var c = new Customer { CustomerID = "ALFKI" };
                context.Customers.Attach(c);
                context.Customers.AsQueryable().ToList();
                Assert.IsNull(c.CompanyName);
                Assert.IsTrue(c.ChangeTracker.ModifiedProperties.Any());
                Assert.IsTrue(c.ChangeTracker.ModifiedProperties.Contains("CompanyName"));
            }
        }

        [TestMethod]
        public void Save()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                //Add
                var psCount = context.Products.AsQueryable().Count();
                var p = new Product { ProductName = "p" };
                context.Products.Add(p);
                context.SaveChanges();
                Assert.AreNotEqual(0, p.ProductID);
                Assert.AreEqual(ObjectState.Unchanged, p.ChangeTracker.State);
                Assert.AreEqual(psCount + 1, context.Products.AsQueryable().ToList().Count);

                //Update
                p.ProductName = "p2";
                Assert.AreEqual(1, p.ChangeTracker.ModifiedProperties.Count);
                Assert.AreEqual("ProductName", p.ChangeTracker.ModifiedProperties[0]);
                context.SaveChanges();
                Assert.IsFalse(p.ChangeTracker.ModifiedProperties.Any());
                context.MergeOption = MergeOption.NoTracking;
                var p2 = context.Products.AsQueryable().Where(pr => pr.ProductID == p.ProductID).First();
                Assert.AreNotEqual(p, p2);
                Assert.AreEqual("p2", p2.ProductName);

                //Remove
                context.Products.Remove(p);
                Assert.AreEqual(ObjectState.Deleted, p.ChangeTracker.State);
                context.SaveChanges();
                Assert.AreEqual(psCount, context.Products.AsQueryable().ToList().Count);
            }
        }

        [TestMethod]
        public void Save2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var csCount = context.Categories.AsQueryable().Count();
                var c1 = new Category { CategoryName = "cn" };
                context.Categories.Add(c1);
                var psCount = context.Products.AsQueryable().Count();
                var p1 = new Product { ProductName = "p1" };
                var p2 = new Product { ProductName = "p2" };
                context.Products.Add(p1);
                context.Products.Add(p2);
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(csCount + 1, context2.Categories.AsQueryable().Count());
                    Assert.AreEqual(psCount + 2, context2.Products.AsQueryable().Count());
                }
                context.Categories.Remove(c1);
                context.Products.Remove(p1);
                p2.ProductName = "p2Bis";
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(csCount, context2.Categories.AsQueryable().Count());
                    Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
                    Assert.AreEqual("p2Bis", context2.Products.Last().ProductName);
                }
                context.Products.Remove(p2);
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(psCount, context2.Products.AsQueryable().Count());
                }
            }
        }

        [TestMethod]
        public void TestSaveManyToMany()
        {
            CustomerDemographic cd;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = context.CustomerDemographics.AsQueryable().Where(c => c.CustomerTypeID == "CD").Include(CustomerDemographic.CUSTOMERS_NAME).FirstOrDefault();
                if (cd != null)
                {
                    context.CustomerDemographics.Remove(cd);
                    context.SaveChanges();
                }
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
                context.CustomerDemographics.Add(cd);
                context.SaveChanges();
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = context.Customers.AsQueryable().First();
                c.CustomerDemographics.Add(cd);
                Assert.AreEqual(ObjectState.Unchanged, cd.ChangeTracker.State);
                Assert.AreEqual(1, context.CustomerDemographics.Count);
                Assert.AreEqual(1, cd.Customers.Count);
                context.SaveChanges();
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = context.Customers.AsQueryable().Include(Customer.CUSTOMERDEMOGRAPHICS_NAME).First();
                Assert.IsTrue(context.CustomerDemographics.Any());
                Assert.IsTrue(cd.Customers.Any());
                context.CustomerDemographics.Remove(context.CustomerDemographics.First(cd2 => cd2.CustomerTypeID.TrimEnd() == "CD"));
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestSaveManyToMany2()
        {
            CustomerDemographic cd;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
                context.CustomerDemographics.Add(cd);
                var c = context.Customers.AsQueryable().First();
                c.CustomerDemographics.Add(cd);
                context.SaveChanges();
                context.CustomerDemographics.Remove(cd);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestSaveManyToMany3()
        {
            CustomerDemographic cd;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
                context.CustomerDemographics.Add(cd);
                var c = context.Customers.AsQueryable().First();
                c.CustomerDemographics.Add(cd);
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(1, (from cd2 in context.CustomerDemographics.AsQueryable().Include(CustomerDemographic.CUSTOMERS_NAME)
                                        where cd2.CustomerTypeID == cd.CustomerTypeID
                                        select cd2).First().Customers.Count);
                }
                c.CustomerDemographics.Remove(cd);
                Assert.IsFalse(cd.Customers.Any());
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.IsFalse((from cd2 in context2.CustomerDemographics.AsQueryable().Include(CustomerDemographic.CUSTOMERS_NAME)
                                    where cd2.CustomerTypeID == cd.CustomerTypeID
                                    select cd2).First().Customers.AsEnumerable().Any());
                }
                context.CustomerDemographics.Remove(cd);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestSaveManyToMany4()
        {
            CustomerDemographic cd;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
                context.CustomerDemographics.Add(cd);
                var c = context.Customers.AsQueryable().First();
                cd.Customers.Add(c);
                context.SaveChanges();
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.CustomerDemographics.Attach(cd);
                context.CustomerDemographics.Remove(cd);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestSaveManyToMany5()
        {
            CustomerDemographic cd;
            Customer c;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                cd = new CustomerDemographic { CustomerTypeID = "CD", CustomerDesc = "cd desc" };
                context.CustomerDemographics.Add(cd);
                c = new Customer { CustomerID = "TUTU", CompanyName = "Company" };
                cd.Customers.Add(c);
                context.SaveChanges();
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.CustomerDemographics.Attach(cd);
                context.CustomerDemographics.Remove(cd);
                context.Customers.Remove(c);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestAddViaCollection()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                int psCount;
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    psCount = context2.Products.AsQueryable().Count();
                }
                var c = context.Categories.AsQueryable().First();
                var p = new Product { ProductName = "pn" };
                c.Products.Add(p);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(1, context.Products.Count);
                Assert.AreEqual(context.Products[0], p);
                Assert.AreEqual(p.Category, c);
                Assert.AreEqual(p.CategoryID, c.Id);
                Assert.AreEqual(ObjectState.Added, p.ChangeTracker.State);
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
                }
                Assert.AreEqual(1, c.Products.Count);
                context.Products.Remove(p);
                Assert.IsFalse(c.Products.Any());
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestAddViaCollection2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                int psCount;
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    psCount = context2.Products.AsQueryable().Count();
                }
                var c = context.Categories.AsQueryable().First();
                var p = new Product { ProductName = "pn", Category = c };
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(1, context.Products.Count);
                Assert.AreEqual(context.Products[0], p);
                Assert.AreEqual(p.Category, c);
                Assert.AreEqual(p.CategoryID, c.Id);
                Assert.AreEqual(ObjectState.Added, p.ChangeTracker.State);
                context.SaveChanges();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    Assert.AreEqual(psCount + 1, context2.Products.AsQueryable().Count());
                }
                Assert.AreEqual(1, c.Products.Count);
                context.Products.Remove(p);
                Assert.IsFalse(c.Products.Any());
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestAddViaCollection3()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { CategoryName = "cn" };
                context.Categories.Add(c);
                var p = new Product { ProductName = "pn", Category = c };
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(1, context.Products.Count);
                Assert.AreEqual(context.Products[0], p);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(c.Id, p.CategoryID);
                Assert.AreEqual(1, context.Categories.Count);
                Assert.AreEqual(c, context.Categories[0]);
                context.SaveChanges();
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(c.Id, p.CategoryID);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
                context.Categories.Remove(c);
                Assert.IsNull(p.Category);
                Assert.IsNull(p.CategoryID);
                Assert.AreEqual(ObjectState.Modified, p.ChangeTracker.State);
                Assert.AreEqual(1, p.ChangeTracker.ModifiedProperties.Count);
                Assert.AreEqual("CategoryID", p.ChangeTracker.ModifiedProperties[0]);
                context.SaveChanges();
                context.Products.Remove(p);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestAddViaCollection4()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { CategoryName = "cn" };
                var p = new Product { ProductName = "pn", Category = c };
                context.Categories.Add(c);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(1, context.Products.Count);
                Assert.AreEqual(context.Products[0], p);
                Assert.AreEqual(p.Category, c);
                Assert.AreEqual(p.CategoryID, c.Id);
                Assert.AreEqual(1, context.Categories.Count);
                Assert.AreEqual(c, context.Categories[0]);
            }
        }

        [TestMethod]
        public void TestAddViaCollection5()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Customer { CustomerID = "A" };
                var cd = new CustomerDemographic();
                c.CustomerDemographics.Add(cd);
                context.Customers.Attach(c);
                Assert.AreEqual(1, context.Customers.Count);
                Assert.AreEqual(1, context.CustomerDemographics.Count);
                Assert.AreEqual(c, context.Customers[0]);
                Assert.AreEqual(cd, context.CustomerDemographics[0]);
                Assert.AreEqual(1, cd.Customers.Count);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestEntitySetAttachWithSameKey()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Categories.Attach(new Category { Id = 1 });
                context.Categories.Attach(new Category { Id = 1 });
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestEntitySetAddWithSameKey()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Customers.Add(new Customer { CustomerID = "C" });
                context.Customers.Add(new Customer { CustomerID = "C" });
            }
        }

        [TestMethod]
        public void TestEntitySetAddWithSameKeyIdentity()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Categories.Add(new Category { Id = 0 });
                context.Categories.Add(new Category { Id = 0 });
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestNavigationPropertyManyAttachWithSameKey()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var cd = new CustomerDemographic { CustomerTypeID = "CD" };
                context.CustomerDemographics.Attach(cd);
                context.Customers.Attach(new Customer { CustomerID = "C" });
                cd.Customers.Attach(new Customer { CustomerID = "C" });
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestNavigationPropertyManyAddWithSameKey()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var cd = new CustomerDemographic { CustomerTypeID = "CD" };
                context.CustomerDemographics.Attach(cd);
                context.Customers.Attach(new Customer { CustomerID = "C" });
                cd.Customers.Add(new Customer { CustomerID = "C" });
            }
        }

        [TestMethod]
        public void MultipleAddAttachOfSameObject()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Customer { CustomerID = "C" };
                context.Customers.Add(c);
                context.Customers.Add(c);
                context.Customers.Attach(c);
                new CustomerDemographic { CustomerTypeID = "CD" }.Customers.Add(c);
                Assert.AreEqual(1, context.Customers.Count);
            }
        }

        [TestMethod]
        public void MultipleRelationAddAttachOfSameObject()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Customer { CustomerID = "C" };
                var cd = new CustomerDemographic { CustomerTypeID = "CD" };
                c.CustomerDemographics.Add(cd);
                c.CustomerDemographics.Add(cd);
                c.CustomerDemographics.Attach(cd);
                Assert.AreEqual(1, c.CustomerDemographics.Count);
                Assert.AreEqual(1, cd.Customers.Count);
            }
        }

        [TestMethod]
        public void DeleteCascadeOneToMany()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var o = new Order();
                var od = new OrderDetail { Order = o };
                Assert.AreEqual(ObjectState.Detached, o.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Detached, od.ChangeTracker.State);
                context.Orders.Add(o);
                Assert.AreEqual(ObjectState.Added, o.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Added, od.ChangeTracker.State);
                context.Orders.Remove(o);
                Assert.AreEqual(ObjectState.Detached, o.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Detached, od.ChangeTracker.State);
            }
        }

        [TestMethod]
        public void DeleteCascadeOneToMany2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var o = new Order();
                var od = new OrderDetail { Order = o, Product = context.Products.AsQueryable().First(), Discount = 0, Quantity = 1, UnitPrice = 10 };
                context.Orders.Add(o);
                context.SaveChanges();
                var od2 = new OrderDetail { Order = o };
                context.Orders.Remove(o);
                Assert.AreEqual(ObjectState.Deleted, o.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Deleted, od.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Detached, od2.ChangeTracker.State);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void DeleteCascadeOneToOne()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var m = new Member { CustomerID = "TATA" };
                var c = new Customer { CustomerID = "TATA", CompanyName = "TOTO", Member = m };
                context.Customers.Add(c);
                context.SaveChanges();
                context.Customers.Remove(c);
                Assert.AreEqual(ObjectState.Deleted, c.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Deleted, m.ChangeTracker.State);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void DeleteCascadeOneToOne2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var m = new Member { CustomerID = "TOTO" };
                var c = new Customer { CustomerID = "TOTO", CompanyName = "TOTO", Member = m };
                context.Customers.Add(c);
                context.Customers.Remove(c);
                Assert.AreEqual(ObjectState.Detached, c.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Detached, m.ChangeTracker.State);
            }
        }

        [TestMethod]
        public void AttachRelationInLoad()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { Id = 1 };
                context.Categories.Attach(c);
                var p = new Product { CategoryID = 1 };
                context.Products.Attach(p);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
            }
        }

        [TestMethod]
        public void AttachRelationInLoad2()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { Id = 1 };
                context.Categories.Add(c);
                var p = new Product { CategoryID = 1 };
                context.Products.Add(p);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
            }
        }

        [TestMethod]
        public void AttachRelationInLoad3()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p = new Product { CategoryID = 1 };
                context.Products.Attach(p);
                var c = new Category { Id = 1 };
                context.Categories.Attach(c);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
            }
        }

        [TestMethod]
        public void AttachRelationInLoad4()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p = new Product { CategoryID = 1 };
                context.Products.Add(p);
                var c = new Category { Id = 1 };
                context.Categories.Add(c);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
            }
        }

        [TestMethod]
        public void AttachRelationInLoad5()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Products.AsQueryable().ToList();
                var c = context.Categories.AsQueryable().First();
                Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
                foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
                {
                    Assert.AreEqual(c, p.Category);
                    Assert.IsTrue(c.Products.Contains(p));
                }
            }
        }

        [TestMethod]
        public void AttachRelationInLoad6()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = context.Categories.AsQueryable().First();
                context.Products.AsQueryable().ToList();
                Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
                foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
                {
                    Assert.AreEqual(c, p.Category);
                    Assert.IsTrue(c.Products.Contains(p));
                }
            }
        }

        [TestMethod]
        public void AttachRelationInLoad7()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Products.AsQueryable().ToList();
                var c = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).First();
                Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
                foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
                {
                    Assert.AreEqual(c, p.Category);
                    Assert.IsTrue(c.Products.Contains(p));
                }
            }
        }

        [TestMethod]
        public void AttachRelationInLoad8()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context.Products.AsQueryable().ToList();
                var c = new Category { Id = 1 };
                context.Categories.Attach(c);
                var c2 = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).First();
                Assert.AreEqual(c, c2);
                Assert.AreEqual(context.Products.Where(p => p.CategoryID == c.Id).Count(), c.Products.Count);
                foreach (var p in context.Products.Where(p => p.CategoryID == c.Id))
                {
                    Assert.AreEqual(c, p.Category);
                    Assert.IsTrue(c.Products.Contains(p));
                }
            }
        }

        [TestMethod]
        public void AttachRelationInLoad9()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { CategoryName = "cn" };
                var p = new Product { ProductName = "pn", Category = c };
                context.Categories.Add(c);
                Assert.AreEqual(1, context.Products.Count);
                context.SaveChanges();
                Product p2;
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    var c2 = context2.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).Where(c3 => c3.Id == c.Id).First();
                    p2 = new Product { ProductName = "pn2" };
                    c2.Products.Add(p2);
                    context2.SaveChanges();
                }
                var c4 = context.Categories.AsQueryable().Include(Category.PRODUCTS_NAME).Where(c3 => c3.Id == c.Id).First();
                Assert.IsFalse(p.IsInitializingRelationships);
                Assert.AreEqual(c, c4);
                Assert.IsTrue(c.Products.Contains(p));
                Assert.IsFalse(c.Products.Contains(p2));
                var p3 = c.Products.First(p4 => p4.ProductID == p2.ProductID);
                Assert.IsFalse(p3.IsInitializingRelationships);
                Assert.IsTrue(c.Products.Contains(p3));
                Assert.IsTrue(context.Products.Contains(p3));
                context.Products.Remove(p3);
                context.Products.Remove(p);
                context.Categories.Remove(c);
                Assert.AreEqual(c.Id, p.CategoryID);
                Assert.AreEqual(c.Id, p3.CategoryID);
                Assert.AreEqual(c4, p.ChangeTracker.ObjectsRemovedFromCollectionProperties["Category"][0]);
                Assert.AreEqual(c4, p3.ChangeTracker.ObjectsRemovedFromCollectionProperties["Category"][0]);
                Assert.AreEqual(2, c4.ChangeTracker.ObjectsRemovedFromCollectionProperties["Products"].Count);
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void AttachRelationInLoad10()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p = context.Products.AsQueryable().First();
                context.Orders.Attach(new Order());
                var od = context.OrderDetailSet.AsQueryable().Where(od2 => od2.ProductID == p.ProductID).First();
                var p2 = (from p3 in context.Products.AsQueryable().Include(Product.CATEGORY_NAME).Include(string.Concat(Product.ORDERDETAILS_NAME, ".", OrderDetail.ORDER_NAME))
                          where p3.ProductID == p.ProductID
                          select p3).First();
                Assert.AreEqual(p, p2);
                Assert.IsNotNull(p.Category);
                Assert.AreEqual(1, context.Categories.Count);
                Assert.AreEqual(p.OrderDetails.Count, context.OrderDetailSet.Count);
                foreach (var od2 in p.OrderDetails)
                    Assert.IsNotNull(od2.Order);
                Assert.AreEqual(p.OrderDetails.Select(od3 => od3.Order).Distinct().Count() + 1, context.Orders.Count);
                Assert.IsTrue(context.Orders.Any());
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AddSameEntityInDifferentContext()
        {
            var p = new Product();
            using (var context1 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context1.Products.Add(p);
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    context2.Products.Add(p);
                }
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AddSameEntityFromServiceInDifferentContext()
        {
            Product p;
            using (var context1 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                p = context1.Products.AsQueryable().First();
                using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
                {
                    context2.Products.Add(p);
                }
            }
        }

        [TestMethod]
        public void AddSameEntityInDifferentContextWithDispose()
        {
            var p = new Product();
            using (var context1 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context1.Products.Add(p);
            }
            using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context2.Products.Add(p);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AddSameEntityInDifferentContextWithDisposeAndConflicts()
        {
            var c = new Category { Id = 1 };
            var p1 = new Product { ProductID = 1, Category = c };
            var p2 = new Product { ProductID = 2, CategoryID = 1 };
            using (var context1 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context1.Categories.Attach(c);
                context1.Products.Attach(p2);
                Assert.AreEqual(2, context1.Products.Count);
                Assert.AreEqual(2, c.Products.Count);
                Assert.AreEqual(c, p2.Category);
            }
            using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p3 = new Product { ProductID = 1, CategoryID = 1 };
                context2.Products.Attach(p3);
                context2.Products.Attach(p2);
            }
        }

        [TestMethod]
        public void AddEntityInDifferentContextWithDispose()
        {
            var c = new Category { Id = 1 };
            var p2 = new Product { ProductID = 2, CategoryID = 1 };
            using (var context1 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                context1.Categories.Attach(c);
                context1.Products.Attach(p2);
            }
            using (var context2 = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p3 = new Product { ProductID = 1, CategoryID = 1 };
                context2.Products.Attach(p3);
                context2.Products.Attach(p2);
                Assert.AreEqual(c, p3.Category);
            }
        }

        [TestMethod]
        public void LoadFromOneToMany()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = context.Categories.AsQueryable().First();
                Assert.IsFalse(c.Products.Any());
                Assert.IsFalse(context.Products.Any());
                var ps = c.LoadProducts();
                Assert.IsTrue(ps.Any());
                Assert.AreEqual(ps.Count, c.Products.Count);
                Assert.AreEqual(ps.Count, context.Products.Count);
                foreach (var p in ps)
                    Assert.AreEqual(c, p.Category);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void LoadFromOneToManyDetached()
        {
            Category c;
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                c = context.Categories.AsQueryable().First();
            }
            var ps = c.LoadProducts();
        }

        [TestMethod]
        public void LoadFromManyToOne()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p = context.Products.AsQueryable().First();
                Assert.IsNull(p.Category);
                Assert.IsFalse(context.Categories.Any());
                var c = p.LoadCategory();
                Assert.IsNotNull(c);
                Assert.AreEqual(c, p.Category);
                Assert.AreEqual(1, context.Categories.Count);
                Assert.AreEqual(1, c.Products.Count);
                Assert.AreEqual(p, c.Products[0]);
            }
        }

        [TestMethod]
        public void LoadFromManyToMany()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = (from cust in context.Customers.AsQueryable()
                         where cust.CustomerID == "VINET"
                         select cust).First();
                Assert.IsFalse(c.CustomerDemographics.Any());
                Assert.IsFalse(context.CustomerDemographics.Any());
                c.LoadCustomerDemographics();
                Assert.IsTrue(c.CustomerDemographics.Any());
                Assert.AreEqual(c.CustomerDemographics.Count, context.CustomerDemographics.Count);
            }
        }

        [TestMethod]
        public void LoadFromOneToOne()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = context.Customers.AsQueryable().First();
                Assert.IsNull(c.Member);
                Assert.IsFalse(context.Members.Any());
                var m = c.LoadMember();
                Assert.IsNotNull(c.Member);
                Assert.AreEqual(1, context.Members.Count);
                Assert.AreEqual(c, m.Customer);
            }
        }

        [TestMethod]
        public void AddIntoBaseEntitySet()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var RetiredEmployee = new RetiredEmployee();
                context.Employees.Attach(RetiredEmployee);
                Assert.AreEqual(1, context.Employees.Count);
                Assert.AreEqual(1, context.OutEmployees.Count);
                Assert.AreEqual(1, context.RetiredEmployees.Count);
            }
        }

        [TestMethod]
        public void GetAllEntitiesWithInheritance()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var l = context.Employees.AsQueryable().ToList();
                Assert.AreEqual(l.Count, context.Employees.Count);
                Assert.AreEqual(l.OfType<OutEmployee>().Count(), context.OutEmployees.Count);
                Assert.AreEqual(l.OfType<RetiredEmployee>().Count(), context.RetiredEmployees.Count);
                Assert.IsTrue(context.RetiredEmployees.Any());
            }
        }

        [TestMethod]
        public void Detach()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c = new Category { Id = 1 };
                context.Categories.Attach(c);
                var p = new Product { CategoryID = 1 };
                context.Products.Attach(p);
                Assert.AreEqual(c, p.Category);
                context.Categories.Detach(c);
                Assert.IsNull(p.Category);
                Assert.AreEqual(c.Id, p.CategoryID);
            }
        }

        [TestMethod]
        public void UpdateFK()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var c1 = new Category { Id = 1 };
                context.Categories.Attach(c1);
                var c2 = new Category { Id = 2 };
                context.Categories.Attach(c2);
                var p = new Product { CategoryID = 1 };
                context.Products.Attach(p);
                Assert.AreEqual(c1, p.Category);
                Assert.AreEqual(1, c1.Products.Count);
                p.CategoryID = 2;
                Assert.AreEqual(1, p.ChangeTracker.ObjectsRemovedFromCollectionProperties.Count);
                Assert.AreEqual(1, p.ChangeTracker.ObjectsRemovedFromCollectionProperties["Category"].Count);
                Assert.AreEqual(c1, p.ChangeTracker.ObjectsRemovedFromCollectionProperties["Category"][0]);
                Assert.AreEqual(c2, p.Category);
                Assert.IsFalse(c1.Products.Any());
                Assert.AreEqual(1, c2.Products.Count);
            }
        }

        [TestMethod]
        public void UpdateNavigationProperty()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p = context.Products.AsQueryable().Include(Product.CATEGORY_NAME).Where(pr => pr.CategoryID == 1).First();
                var c1 = p.Category;
                var c2 = context.Categories.AsQueryable().First(c => c.Id == 2);
                Assert.AreEqual(c1, p.Category);
                Assert.AreEqual(1, c1.Products.Count);
                Assert.IsFalse(c2.Products.Any());
                p.Category = c2;
                Assert.AreEqual(c2, p.Category);
                Assert.IsFalse(c1.Products.Any());
                Assert.AreEqual(1, c2.Products.Count);
                Assert.AreEqual(ObjectState.Modified, p.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Unchanged, c1.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Unchanged, c2.ChangeTracker.State);
                Assert.AreEqual(1, p.ChangeTracker.ObjectsRemovedFromCollectionProperties.Count);
                Assert.AreEqual(1, c1.ChangeTracker.ObjectsRemovedFromCollectionProperties.Count);
                Assert.AreEqual(1, c2.ChangeTracker.ObjectsAddedToCollectionProperties.Count);
                context.SaveChanges();
                Assert.AreEqual(ObjectState.Unchanged, p.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Unchanged, c1.ChangeTracker.State);
                Assert.AreEqual(ObjectState.Unchanged, c2.ChangeTracker.State);
                Assert.IsFalse(p.ChangeTracker.ObjectsRemovedFromCollectionProperties.Any());
                Assert.IsFalse(c1.ChangeTracker.ObjectsRemovedFromCollectionProperties.Any());
                Assert.IsFalse(c2.ChangeTracker.ObjectsAddedToCollectionProperties.Any());
                p.Category = c1;
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void TestNullParameter()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var p1 = context.Products.AsQueryable().FirstOrDefault(p => p.CategoryID == null);
                var p2 = context.Products.AsQueryable().FirstOrDefault(p => !p.CategoryID.HasValue);
                Assert.AreEqual(p1, p2);
            }
        }

        [TestMethod]
        public void TestLazyLoadingOnEntitySet()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = true })
            {
                Assert.IsTrue(context.Categories.Any());
            }
            using (var context = new NorthwindClientContext())
            {
                var c = context.Categories.AsQueryable().First();
                context.LazyLoadingEnabled = false;
                Assert.AreEqual(1, context.Categories.Count);
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                Assert.IsFalse(context.Categories.Any());
            }
            using (var context = new NorthwindClientContext())
            {
                Assert.IsFalse(context.Categories.Any());
            }
        }

        [TestMethod]
        public void TestLazyLoadingOnNavigationPropertyMany()
        {
            using (var context = new NorthwindClientContext())
            {
                var category = context.Categories.AsQueryable().First();
                Assert.IsTrue(category.Products.Any());
            }
            using (var context = new NorthwindClientContext())
            {
                context.Categories.LazyLoadingEnabled = false;
                var category = context.Categories.AsQueryable().First();
                Assert.IsFalse(category.Products.Any());
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var category = context.Categories.AsQueryable().First();
                Assert.IsFalse(category.Products.Any());
            }
        }

        [TestMethod]
        public void TestLazyLoadingOnNavigationPropertyOne()
        {
            using (var context = new NorthwindClientContext())
            {
                var product = context.Products.AsQueryable().First();
                Assert.IsNotNull(product.Category);
            }
            using (var context = new NorthwindClientContext())
            {
                context.Products.LazyLoadingEnabled = false;
                var product = context.Products.AsQueryable().First();
                Assert.IsNull(product.Category);
            }
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = false })
            {
                var product = context.Products.AsQueryable().First();
                Assert.IsNull(product.Category);
            }
        }

        [TestMethod]
        public void TestLazyLoadingAndInclude()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = true })
            {
                var orders = context.Orders.AsQueryable().Include(o => o.OrderDetails).Include(o => o.Customer).ToList();
                Assert.IsTrue(orders.Any(o => o.Customer != null));
                foreach (var order in orders.Where(o => o.Customer != null))
                {
                    Assert.IsNull(order.LazyLoadCustomer);
                    Assert.IsNull(order.LazyLoadOrderDetails);
                    Assert.IsNotNull(order.LazyLoadEmployee);
                    Assert.IsNotNull(order.Customer.LazyLoadOrders);
                    foreach (var od in order.OrderDetails)
                        Assert.IsNull(od.LazyLoadOrder);
                }
            }
        }

        [TestMethod]
        public void TestLazyLoadingAndIncludeManyToMany()
        {
            using (var context = new NorthwindClientContext { LazyLoadingEnabled = true })
            {
                var customers = context.Customers.AsQueryable().Where(c => c.CustomerDemographics.Any()).Include(c => c.CustomerDemographics).Take(2).ToList();
                foreach (var customer in customers)
                {
                    Assert.IsNull(customer.LazyLoadCustomerDemographics);
                    foreach (var cd in customer.CustomerDemographics)
                        Assert.IsNotNull(cd.LazyLoadCustomers);
                }
            }
        }
    }
}
